home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part1 / 5297 < prev    next >
Encoding:
Internet Message Format  |  1996-08-05  |  4.4 KB

  1. Path: newsfeed.direct.ca!usenet
  2. From: qjackson@direct.ca
  3. Newsgroups: comp.lang.c++
  4. Subject: Re: How to handle error in constructor
  5. Date: Sat, 03 Feb 1996 16:03:59 GMT
  6. Organization: Parsepolis Software
  7. Message-ID: <4f00u4$s5n@orb.direct.ca>
  8. References: <DLyyIM.5EG@teslab.lab.oz.au>
  9. Reply-To: qjackson@direct.ca
  10. NNTP-Posting-Host: 204.174.245.169
  11. X-Newsreader: Forte Free Agent 1.0.82
  12.  
  13. andrew@teslab.lab.oz.au (Andrew Phillips) wrote:
  14.  
  15. >I'm converting and enhancing a simple program in C to C++.  Without going
  16. >into too much detail I have a class that represents a file on disk.  The
  17. >contructor opens the file, but what should it do if the file cannot be
  18. >opened?  The C program just calls fopen() tests the return value and 
  19. >if there's an error it prints a message and exits.
  20.  
  21. >In C++ I thought to set a flag in the constructor and have a member function
  22. >that tests the flag to see if the file was opened correctly.  This seems
  23. >rather inelegant -- I guess exceptions would be the elegant way but seem
  24. >like overkill for such a simple program.  I've looked in several C++ books but
  25. >error handling is given scant coverage except for exception handling.
  26.  
  27. >Any suggestions would be greatly appreciated.
  28.  
  29. Hello, Andrew!
  30.  
  31. I am currently designing a class (or rather, a hierarchy of classes
  32. that act as one class in the end)that parses a string as part of the
  33. construction process.  I can't throw exceptions because the version of
  34. the Turbo C++ compiler that I am using (3.00) doesn't have exception
  35. handling.  What's more, I'm not sure I would want to throw and catch
  36. even if I had the ball and glove.
  37.  
  38. Since construction of an object of the LpmRule class involves about 15
  39. subprocesses, any number of errors can occur during the construction
  40. of such an object.  I have considered this eventuality and pass an
  41. explicit ErrorCode parameter to each sub-function under the
  42. constructor.  The construction itself reads, in part:
  43.  
  44. LpmTokenizer::LpmTokenizer 
  45. (
  46.   shuString& theRule
  47. )
  48. {
  49.  
  50.   StateType ErrorCode;
  51.   STR_LENGTH ErrorPtr;
  52.  
  53.   parse
  54.   (
  55.       theRule_,
  56.       "",
  57.       FALSE,
  58.       ErrorCode,
  59.       ErrorPtr
  60.   );
  61.  
  62.   if (ErrorCode)
  63.   {
  64.       errorCleanUp();  // this function detaches all objects attached
  65.                // to this class by pointers using 'delete'
  66.  
  67.       lastError_ = ErrorCode;
  68.       errorPtr_  = ErrorPtr;
  69.   }
  70.   else
  71.   {
  72.       lastError_ = (StateType)0;
  73.       errorPtr_ = (STR_LENGTH)0;
  74.   }
  75.  
  76. }
  77.  
  78. //////
  79.  
  80.  
  81. Suppose I construct an LpmTokenizer object with a bad string:
  82.  
  83.   LpmTokenizer myRule = "[['this is bad becase there are two [s'$";
  84.  
  85. If I'm not sure that it will parse correctly, I check like this:
  86.  
  87.     if (myRule.lastError() != STATE_NO_ERROR)
  88.     {
  89.     cout << "Rule didn't parse properly!" << "\n";
  90.     exit(myRule.lastError());
  91.     }
  92.  
  93. I realize this is not in keeping with throwing and catching
  94. methodology, but as I said, the compiler under which I am developing
  95. this class does not have exception handling.
  96.  
  97. Moreover, since LpmRule objects may be created to and fro in string
  98. comparison expressions on the fly, I did it this way rather than using
  99. an 'init' member function in order to allow temporary casts using the
  100. following syntax:
  101.  
  102.     if ((LpmRule)"['C';'C++'$" == "C")
  103.     {
  104.         cout << "String is either \"C\" or \"C++\"" << "\n";
  105.     }
  106.  
  107. This type of thing wouldn't be as easily expressed if I had to
  108. construct and then initialize as separate steps:
  109.  
  110.     LpmRule myRule;
  111.     myRule.init("['C';'C++'$");
  112.  
  113.     if (myRule == "C")
  114.     {
  115.         cout << "String is either \"C\" or \"C++\"" << "\n";
  116.     }
  117.  
  118. (The first method eats up less name space, since anonymous objects can
  119. be created if they're needed for quick comparisons.)
  120.  
  121. The only caution is that you must be sure to check your error flag
  122. before doing anything critical with such an object, if the constructor
  123. can fail.  In the case of LpmRule -- it is assumed that any "hard
  124. coded" rule will be known to parse properly, whereas any user supplied
  125. rule will not be known to parse.  The programmer will be able to take
  126. advantage of this fact and will therefore only have to do explicit
  127. assertion checking when the object is being constructed with an
  128. unknown string.  (Although changes in the underlying syntax still make
  129. it prudent to do explicit assertion checks even if the hardcoded rules
  130. are known to parse.)
  131.  
  132.  
  133. Cheers,
  134.  
  135.  
  136.  
  137.  
  138. --                           
  139.                            | 
  140.     Parsepolis Software    |   Quinn Tyler Jackson
  141.         "ParseCity"        |     (aka 'Jamshid')
  142. >--------------------------|   qjackson@direct.ca
  143.                            |---------------------->
  144.  
  145.